// ============================================================================
// Implementation file for myrpcgen
//
// Solution for CPSC 4780 Fall 2010 Group Project
// Fei Wang and  Brad Tudor
// April 8, 2011
//
// read the .x file and create .h, _clnt.c, & _svc.c
// ==========================================================================

#include <string>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <fstream>

using namespace std;
// ==========================================================================
//structures that will store values
//used in generation of new files.
// ==========================================================================
struct defines                        
{                                      
   string name;
   string value;
};

struct program
{
      string name;
      string namelower;
      string number;
};

struct functions
{
      string name;
      string namelower;
      string type;            // return type
      string typearg;         // arg type
      string value;
};

defines def[50];
                  //declaring structures/variables to use for parsing/counting
int countdef = 0;

program prog;

functions funct[50];

int countfunct = 0;

int countmain = 0;

int main(int argc, char *argv[])
{
   if (argc != 2)
   {
      cout << "Usage: " << argv[0] << " <*.x>" << endl;

      exit(1);
   }
   ifstream infile;
   //opening *.x file.
   infile.open(argv[1]);
   if(!infile) 
   {
      cout << "Can NOT open the file !" << endl;
      exit(1);
   }
   
   string shortname = argv[1];
                                 //grabbing the name of the interface file.
   shortname.erase(shortname.find_last_not_of(".x")+1);

   string shortnamecaps = shortname;
                 // manipulating filename for later use when writing to files.
   for(unsigned int i = 0; i < shortnamecaps.length(); i++)
   {
      shortnamecaps[i] = toupper(shortnamecaps[i]);
   } 
   string line;   // declaring strings to use for string operations.  
   
   string buffer; //used for grabbing values from .x file
  
   while (getline(infile, line))    // start getting info from .x file
                                    // and putting it in correspnding structs.
   {
      istringstream iss(line);

      if (line[0] == '#')        //putting defines in defines struct
	 {
	    while (iss >> buffer)
	    {   
	       if (countmain == 1)
	       {		  
		  def[countdef].name = buffer;    
	       }
	       if (countmain == 2)
	       {
		  def[countdef].value = buffer;
	       }
	       countmain++;
	    }
	    countmain = 0;
	    countdef++;
	 }
      if (line[0] == 'p' && line[1] == 'r' && line[2] == 'o' && line[3] == 'g'
	  && line[4] == 'r' && line[5] == 'a' && line[6] == 'm')
      {                                   
	 while (iss >> buffer)                
	 {                               //getting program name
	    if (countmain == 1)
	    {
	       prog.name = buffer;

	       prog.namelower = buffer;

	       for(unsigned int i = 0; i < prog.namelower.length(); i++)
	       {
		  prog.namelower[i] = tolower(prog.namelower[i]);
	       }
	    }
	    countmain++;
	 }
	 countmain = 0;
      }
      if (line[0] == ' ' && line[1] == ' ')
      {
	 while (iss >> buffer)
	 {                    //putting functions in function struct  	    
	    if (countmain == 0)
	    {	             	       
	       funct[countfunct].type = buffer;
	    }
	    if (countmain == 1)    
	    {     
	       if (buffer.find_last_of("(int)")+1) //seperating funct.name from
	       {                                       //func.typearg
		  funct[countfunct].typearg = "int";
		  
		  buffer.erase(buffer.find_last_not_of("(int)")+1);
	       }  	       
	    
	       if (buffer.find_last_of("(float)")+1)
	       {
		  funct[countfunct].typearg = "float";
		  
		  buffer.erase(buffer.find_last_not_of("(float)")+1);
	       }

	       if (buffer.find_last_of("(char)")+1)
	       {
		  funct[countfunct].typearg = "char";
		  
		  buffer.erase(buffer.find_last_not_of("(char)")+1);
	       }
	       
	       funct[countfunct].name = buffer; //getting only funct name
	       
	       funct[countfunct].namelower = buffer;
	       
	       for(unsigned int i = 0; i < funct[countfunct].namelower.length(); i++)
	       {                         
		  funct[countfunct].namelower[i]              //converting funct name to lowercase
		     = tolower(funct[countfunct].namelower[i]);
	       }	       
	    }
	    if (countmain == 3)
	    {
	       buffer.erase(buffer.find_last_not_of(";")+1);
	       	       
	       funct[countfunct].value = buffer;
	    } 
	    countmain++;
	 }
	 countmain = 0;
	 countfunct++;
      }
      if (line[0] == '}')
      {	 
	 while (iss >> buffer)
	 {                               //getting program number
	    buffer.erase(buffer.find_last_not_of(";")+1);
	    
	    if (countmain == 2)
	    {
	       prog.number = buffer;
	    }
	    countmain++;
	 }
	 countmain = 0;
      } 
   }
   infile.close();
                           // now generating files!
                           //*.h first!
   ofstream headerfile;

   string shortnamecopy = shortname;
   
   shortnamecopy.append(".h");             //stupid string/char conversions.

   char *tempname = (char*)shortnamecopy.c_str();
   
   headerfile.open(tempname);
   //now writing to file
   headerfile << "/*" << endl << " * Please do not edit this file." << endl
	      << " * It was generated using myrpcgen." << endl << " */"
	      << endl << endl
      
	      << "#ifndef _" << shortnamecaps << "_H_MYRPCGEN" << endl
	      << "#define _" << shortnamecaps << "_H_MYRPCGEN" << endl << endl;
   headerfile << "#include \"Myrpc.h\"" << endl << endl;
   for (int i = 0; i < countdef; i++)    //defines
   {
      headerfile << "#define " << def[i].name << " " << def[i].value << endl;
   }
   headerfile << endl << "#define " << prog.name << " " << prog.number //program
	      << endl << endl;
   
   for (int i = 0; i < countfunct; i++)  //functions
   {
      headerfile << "#define " << funct[i].name << " " << funct[i].value << endl
		 << funct[i].type << " * " << funct[i].namelower << "_"
		 << funct[i].value << "(" << funct[i].typearg << " *,CLIENT *);"
		 << endl << funct[i].type << " * " << funct[i].namelower << "_"
		 << funct[i].value << "_svc(" << funct[i].typearg << "* );"
		 << endl << endl;
   }
   headerfile << "#endif /* !_" << shortnamecaps << "_H_MYRPCGEN */" << endl; 
   
   headerfile.close();           // *.h file done!
                                 // clnt.c next!
   ofstream clientfile;

   shortnamecopy = shortname;
   
   shortnamecopy.append("_clnt.c");             //stupid string/char conversions.

   char *tempname2 = (char*)shortnamecopy.c_str();

   clientfile.open(tempname2);

   clientfile << "/*" << endl << " * Please do not edit this file." << endl
	      << " * It was generated using myrpcgen." << endl << " */"
	      << endl << endl

	      << "#include \"" << shortname << ".h\"" << endl << endl;
   
   for (int i = 0; i < countdef; i++)    //defines
   {
      clientfile << "#define " << def[i].name << " " << def[i].value << endl;
   }
   clientfile << endl;

   for (int i = 0; i < countfunct; i++)  //functions
   {
      clientfile << funct[i].type << " *" << endl << funct[i].namelower
		 << "_" << funct[i].value << "(" << funct[i].typearg
		 << " * argp, CLIENT *clnt)" << endl << "{" << endl   
		 << "     " << "static " << funct[i].type << " clnt_res;"
		 << endl << endl << "     if(my_clnt_call (clnt, "
		 << funct[i].name
		 << ", my_xdr_" << funct[i].typearg << ",(char*) argp," << endl
		 << "       my_xdr_" << funct[i].type << ", (char*)&clnt_res)) {" << endl
		 << "       return (NULL);" << endl << "     }" << endl
		 << "     return (&clnt_res);" << endl << "}" << endl << endl;
   }
   clientfile.close();
                                     // _clnt.c files done!
                                     // now _svc.c!
   ofstream serverfile;

   shortnamecopy = shortname;

   shortnamecopy.append("_svc.c");             //stupid string/char conversions.

   char *tempname3 = (char*)shortnamecopy.c_str();

   serverfile.open(tempname3);

   serverfile << "/*" << endl << " * Please do not edit this file." << endl
	      << " * It was generated using myrpcgen." << endl << " */"
	      << endl << endl

	      << "#include \"" << shortname << ".h\"" << endl
	      << "#include <stdio.h>" << endl
	      << "#include <stdlib.h>" << endl
	      << "#include <string.h>" << endl
	      << "#include <sys/socket.h>" << endl
	      << "#include <netinet/in.h>" << endl << endl;



   for (int i = 0; i < countdef; i++)    //defines
   {
      serverfile << "#define " << def[i].name << " " << def[i].value << endl;
   }
   serverfile << endl << "static void" << endl << prog.namelower << "_1"
	      << "(int switchValue, ServerSocket * RPC_sock)" << endl << "{"
	      << endl << "     switch (switchValue) {" << endl << endl; 

   for(int i = 0; i < countfunct; i++)
   {                                         //functions
      serverfile << "     case " << funct[i].name << ":" << endl
                 << "     {"<< endl    
		 << "          " << funct[i].typearg << " argument;" << endl
		 << "          if(!my_svc_getargs(RPC_sock, my_xdr_"
		 << funct[i].typearg << ",(char*) &argument))" << endl
		 << "          {" << endl
		 << "                 printf ( \"unable to get argument \\n\");" << endl
		 << "               return;" << endl
		 << "          }" << endl
		 << "          if(!my_svc_sendreply(RPC_sock, my_xdr_"
		 << funct[i].type << ",(char*)" <<funct[i].namelower <<"_" << funct[i].value <<"_"
		 << "svc(&argument)" << "))" << endl
		 << "          {" << endl
		 << "                 printf ( \"unable to send reply \\n\");" << endl
		 << "               return;" << endl
		 << "          }" << endl 
		 << "      }" << endl
		 << "          break;" << endl << endl;
   }
   
   serverfile << "     default:" << endl
              << "          printf ( \"unknow proc request \\n\");" << endl
	      << "          return;" << endl;

   serverfile << "     }" << endl << "     return;"
	      << endl << "}" << endl << endl; 
   
   serverfile << "int main (int argc, char **argv)" << endl << "{" << endl
	      << "     SVCXPRT* Transp = my_svcudp_create(0);" << endl
      	      << endl << "     if(Transp == NULL)" << endl << "     {" <<endl
	      << "          printf ( \"unable to create UDP \\n\");" << endl
	      << "          exit(1);" << endl << "     }" << endl
	      << "     if (!my_svc_register(Transp, " << prog.name << "))"  //<< prog.namelower << "_1,
              << endl << "     {" << endl
	      << "          printf ( \"unable to register \\n\");" << endl
	      << "          exit(1);" << endl << "     }" << endl << endl;

   serverfile << "     my_svc_run(Transp,"<< prog.namelower << "_1);" << endl
	      << "     exit(1);" << endl
	      << "     /* NOTREACHED */" << endl << "}" << endl;
   
   serverfile.close();              // Done!

   return 0;
}
